<!doctype html>
<!--
@license
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE
The complete set of authors may be found at http://polymer.github.io/AUTHORS
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS
-->
<html>
<head>
  <meta charset="UTF-8">
  <title>iron-list test</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">

  <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
  <script src="../../web-component-tester/browser.js"></script>
  <script src="../../test-fixture/test-fixture-mocha.js"></script>
  <script src="../../iron-test-helpers/mock-interactions.js"></script>

  <link rel="import" href="fixtures/helpers.html">
  <link rel="import" href="fixtures/x-list.html">

</head>
<body>

  <test-fixture id="trivialList">
    <template>
      <x-list></x-list>
    </template>
  </test-fixture>

<script>
  'use strict';
  suite('basic features', function() {
    var list, container;

    setup(function() {
      container = fixture('trivialList');
      list = container.list;
    });

    test('first item should be focusable', function(done) {
      container.data = buildDataSet(100);

      flush(function() {
        assert.notEqual(getFirstItemFromList(list).tabIndex, -1);
        done();
      });
    });

    test('focus the first item and then reset the items', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        getFirstItemFromList(list).focus();

        simulateScroll({
          list: list,
          contribution: 200,
          target: 3000,
          onScrollEnd: function() {
            list.items = [];
            flush(function() {
              done();
            });
          }
        });
      });
    });

    test('focus the first item and then splice all the items', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        getFirstItemFromList(list).focus();

        simulateScroll({
          list: list,
          contribution: 200,
          target: 3000,
          onScrollEnd: function() {
            list.splice('items', 0, list.items.length);
            flush(function() {
              done();
            });
          }
        });
      });
    });

    test('blur when focused item is removed (#336)', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        getFirstItemFromList(list).focus();

        assert.notEqual(document.activeElement, document.body);

        list.splice('items', 0, 1);

        // HACK(keanulee): This test fails in IE11 if the window is not focused, so
        // skip this test in that case.
        if (document.hasFocus()) {
          assert.equal(document.activeElement, document.body);
        }
        done();
      });
    });

    test('don\'t blur if no items are added or removed', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        getFirstItemFromList(list).focus();

        assert.notEqual(document.activeElement, document.body);

        list.items[0]['foo'] = 'bar';
        list.notifySplices('items', [{
          index: 0,
          addedCount: 0,
          object: list.items,
          type: 'splice',
          removed: []
        }]);

        assert.notEqual(document.activeElement, document.body);
        done();
      });
    });

    test('don\'t blur when items changed (#449)', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        var button = document.createElement('button');
        list.parentNode.appendChild(button);
        button.focus();

        assert.notEqual(document.activeElement, document.body);

        list.items = buildDataSet(100);

        assert.notEqual(document.activeElement, document.body);
        done();
      });
    });

    test('don\'t blur when activeElement is not a descendant of the list (#505, #507)', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        var button = document.createElement('button');
        list.parentNode.appendChild(button);
        button.focus();

        assert.notEqual(document.activeElement, document.body);

        list.splice('items', 0, 1);

        assert.notEqual(document.activeElement, document.body);
        done();
      });
    });

    test('focusItem()', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        var i = 1;
        var item = getNthItemFromList(list, i);

        assert.equal(item.tabIndex, -1);

        list.focusItem(i);

        assert.equal(item.tabIndex, 0);
        done();
      });
    });

    test('should not hide the list', function(done) {
      container.useTabIndex = true;
      list.items = buildDataSet(100);

      flush(function() {
        // this index isn't rendered yet
        list._focusedIndex = list.items.length-1;
        list.scrollTarget.addEventListener('scroll', function() {
          var rect = list.getBoundingClientRect();
          assert.isTrue(rect.top + rect.height > 0);
          done();
        });
        // trigger the scroll event
        list._scrollTop = 1000;
      });
    });

    test('list focus change with down arrow', function(done) {
      container.useTabIndex = true;
      list.items = buildDataSet(100);

      flush(function() {
        var initialItem = getFirstItemFromList(list);
        var itemToFocus = getNthItemFromList(list, 1);
        initialItem.focus();
        flush(function() {
          MockInteractions.pressAndReleaseKeyOn(list, 40); // down
          flush(function() {
            assert.notEqual(itemToFocus.tabIndex, -1);
            done();
          });
        });
      });
    });

    test('list focus change with down arrow after removing item (#512)', function(done) {
      container.useTabIndex = true;
      list.items = buildDataSet(100);
      list.splice('items', 0, 1);

      flush(function() {
        var initialItem = getFirstItemFromList(list);
        var itemToFocus = getNthItemFromList(list, 1);
        initialItem.focus();
        flush(function() {
          MockInteractions.pressAndReleaseKeyOn(list, 40); // down
          flush(function() {
            assert.notEqual(itemToFocus.tabIndex, -1);
            done();
          });
        });
      });
    });

    test('list focus change with up arrow', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        var initialItem = getNthItemFromList(list, 1);
        var itemToFocus = getFirstItemFromList(list);
        initialItem.focus();
        flush(function() {
          MockInteractions.pressAndReleaseKeyOn(list, 38); // up
          flush(function() {
            assert.notEqual(itemToFocus.tabIndex, -1);
            done();
          });
        });
      });
    });

    test('up arrow when first item has focus, defaultPrevented is false', function(done) {
      list.items = buildDataSet(2);
      flush(function() {
        getNthItemFromList(list, 0).focus();
        var handler = e => {
          document.removeEventListener('keydown', handler);
          assert.isFalse(e.defaultPrevented);
          done();
        };
        document.addEventListener('keydown', handler);
        MockInteractions.pressAndReleaseKeyOn(list, 38); // up
      });
    });

    test('down arrow when last item has focus, defaultPrevented is false', function(done) {
      list.items = buildDataSet(2);
      flush(function() {
        getNthItemFromList(list, 1).focus();
        var handler = e => {
          document.removeEventListener('keydown', handler);
          assert.isFalse(e.defaultPrevented);
          done();
        };
        document.addEventListener('keydown', handler);
        MockInteractions.pressAndReleaseKeyOn(list, 40); // down
      });
    });

    test('up arrow when second item has focus, defaultPrevented is true', function(done) {
      list.items = buildDataSet(2);
      flush(function() {
        getNthItemFromList(list, 1).focus();
        var handler = e => {
          document.removeEventListener('keydown', handler);
          assert.isTrue(e.defaultPrevented);
          done();
        };
        document.addEventListener('keydown', handler);
        MockInteractions.pressAndReleaseKeyOn(list, 38); // up
      });
    });

    test('down arrow when second to last item has focus, defaultPrevented is true', function(done) {
      list.items = buildDataSet(2);
      flush(function() {
        getNthItemFromList(list, 0).focus();
        var handler = e => {
          document.removeEventListener('keydown', handler);
          assert.isTrue(e.defaultPrevented);
          done();
        };
        document.addEventListener('keydown', handler);
        MockInteractions.pressAndReleaseKeyOn(list, 40); // down
      });
    });

    test('first click recognized in long lists (#411)', function(done) {
      list.items = buildDataSet(100);

      Polymer.dom.flush();

      list.scroll(0, getFirstItemFromList(list).offsetHeight * list._physicalCount);

      requestAnimationFrame(function() {
        setTimeout(function() {
          var lastOffscreenFocusedItem = list._offscreenFocusedItem;
          var firstItem = getFirstItemFromList(list);
          MockInteractions.focus(firstItem.parentNode);

          Polymer.dom.flush();

          assert.equal(firstItem, getFirstItemFromList(list),
            'Should be the same item after focusing it');
          assert.isNull(lastOffscreenFocusedItem.parentNode,
            'Should remove the last offscreen focused item');
          done();
        });
      });
    });

    test('focus is correctly restored after scrolling off screen (#537)', function(done) {
      list.items = buildDataSet(100);

      flush(function() {
        list.scroll(0, 5000);
        requestAnimationFrame(function() {
          setTimeout(function() {
            var item = getFirstItemFromList(list);
            assert.equal(item.tabIndex, -1);
            MockInteractions.focus(item);
            assert.equal(item.tabIndex, 0);
            list.scroll(0, 0);
            requestAnimationFrame(function() {
              setTimeout(function() {
                MockInteractions.focus(item);
                assert.equal(list._focusedItem, item.parentElement);
                done();
              });
            });
          });
        });
      });
    });

  });

</script>

</body>
</html>
